/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.util.datatransfer;
import java.io.IOException;
import java.awt.datatransfer.*;
import java.util.Hashtable;
import java.util.Enumeration;
import javax.swing.event.EventListenerList;
// and holding a list of services built over data flavors. [???]
/** Extended clipboard that supports listeners that can be notified about
* changes of content. Also contains support for attaching content convertors.
*
* @author Jaroslav Tulach
*/
public abstract class ExClipboard extends Clipboard {
/** listeners */
private EventListenerList listeners = new EventListenerList ();
/** Make a new clipboard.
* @param name name of the clipboard
*/
public ExClipboard (String name) {
super (name);
}
/** Add a listener to clipboard operations.
* @param list the listener
*/
public final void addClipboardListener (ClipboardListener list) {
listeners.add (ClipboardListener.class, list);
}
/** Remove a listener to clipboard operations.
* @param list the listener
*/
public final void removeClipboardListener (ClipboardListener list) {
listeners.remove (ClipboardListener.class, list);
}
/** Fires event about change of content in the clipboard.
*/
protected final void fireClipboardChange () {
Object[] l = listeners.getListenerList ();
ClipboardEvent ev = null;
for (int i = l.length - 2; i >= 0; i -= 2) {
ClipboardListener list = (ClipboardListener)l[i + 1];
if (ev == null) {
ev = new ClipboardEvent (this);
}
list.clipboardChanged (ev);
}
}
/** Obtain a list of convertors assigned to
* this clipboard.
* @return the convertors
*/
protected abstract Convertor[] getConvertors ();
/** Method that takes a transferable, applies all convertors,
* and creates a new transferable using the abilities of the
* convertors.
* <P>
* This method is used when the contents of the clipboard are changed and
* also can be used by Drag & Drop to process transferables between source
* and target.
* <p>
* Note that it is possible for the results to vary according to order
* of the convertors as specified by {@link #getConvertors}. For example,
* the input transferable may contain flavor A, and there may be a convertor
* from A to B, and one from B to C; flavor B will always be available, but
* flavor C will only be available if the convertor list is in the order
* that these were mentioned. If it is desired, the APIs could be enhanced
* to specify a partial ordering of convertors in the manifest.
*
* @param t input transferable
* @return new transferable
*/
public Transferable convert (Transferable t) {
Convertor[] convertors = getConvertors ();
for (int i = 0; i < convertors.length; i++)
t = convertors[i].convert (t);
return t;
}
/** Notifies the transferable that it has been accepted by a drop.
* Works only for ExTransferable, other types of transferables are
* not notified.
*
* @param t transferable to notify its listeners
* @param action which action has been performed
*/
public static void transferableAccepted (Transferable t, int action) {
if (t instanceof ExTransferable) {
((ExTransferable)t).fireAccepted (action);
}
}
/** Notifies the transferable that it has been rejected by a drop.
* Works only for ExTransferable, other types of transferables are
* not notified.
*
* @param t transferable to notify its listeners
*/
public static void transferableRejected (Transferable t) {
if (t instanceof ExTransferable) {
((ExTransferable)t).fireRejected ();
}
}
/** Notifies the transferable that it has lost ownership in clipboard.
* Works only for ExTransferable, other types of transferables are
* not notified.
*
* @param t transferable to notify its listeners
*/
public static void transferableOwnershipLost (Transferable t) {
if (t instanceof ExTransferable) {
((ExTransferable)t).fireOwnershipLost ();
}
}
/** Convertor that can convert the {@link Transferable contents} of a clipboard to
* additional {@link DataFlavor flavors}.
*/
public static interface Convertor {
/** Convert a given transferable to a new transferable,
* generally one which adds new flavors based on the existing flavors.
* The recommended usage is as follows:
*
* <br><code><pre>
* public Transferable convert (final Transferable t) {
* if (! t.isDataFlavorSupported (fromFlavor)) return t;
* if (t.isDataFlavorSupported (toFlavor)) return t;
* ExTransferable et = ExTransferable.create (t);
* et.put (new ExTransferable.Single (toFlavor) {
* public Object getData () throws IOException, UnsupportedFlavorException {
* FromObject from = (FromObject) t.getTransferData (fromFlavor);
* ToObject to = translateFormats (from);
* return to;
* }
* });
* return et;
* }
* </pre></code>
*
* <br>Note that this does not perform the conversion until <code>toFlavor</code> is
* actually requested, nor does it advertise <code>toFlavor</code> as being available
* unless <code>fromFlavor</code> already was.
*
* <p>You may also want to convert some flavor to a node selection, in which case you should do:
*
* <br><code><pre>
* public Transferable convert (final Transferable t) {
* if (! t.isDataFlavorSupported (DataFlavor.stringFlavor)) return t;
* if (NodeTransfer.findPaste (t) != null) return t;
* ExTransferable et = ExTransferable.create (t);
* et.put (NodeTransfer.createPaste (new NodeTransfer.Paste () {
* public PasteType[] types (Node target) {
* if (isSuitable (target)) {
* return new PasteType[] { new PasteType () {
* public Transferable paste () throws IOException {
* try {
* String s = (String) t.getTransferData (DataFlavor.stringFlavor);
* addNewSubnode (target, s);
* } catch (UnsupportedFlavorException ufe) {
* throw new IOException (ufe.toString ());
* }
* return t;
* }
* }};
* } else {
* return new PasteType[0];
* }
* }
* }));
* return et;
* }
* </pre></code>
*
* <p>Convertors should generally avoid removing flavors from the transferable,
* or changing the data for an existing flavor.
*
* @param t the incoming basic transferable
* @return a possible enhanced transferable
*/
public Transferable convert (Transferable t);
}
}
/*
* Log
* 8 Gandalf 1.7 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 7 Gandalf 1.6 9/22/99 Jesse Glick ExClipboard.Convertor
* changed signature to accommodate converting to node selection.
* 6 Gandalf 1.5 6/30/99 Jaroslav Tulach Drag and drop support
* 5 Gandalf 1.4 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 4 Gandalf 1.3 3/10/99 Jesse Glick [JavaDoc]
* 3 Gandalf 1.2 2/21/99 Jaroslav Tulach Clipboard convertors
* 2 Gandalf 1.1 2/10/99 Jaroslav Tulach Clipboard improved.
* 1 Gandalf 1.0 1/5/99 Ian Formanek
* $
*/